﻿using System;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using WordNet.Core.ElementContracts;
using WordNet.Core;
using UnitTestDataProvider.TestClasses;
using WordNet.Core.DataContract;
using Moq;
using DataFileProvider;

namespace UnitTestDataProvider
{
    [TestClass]
    public class IndexWordUnitTest
    {
        [ClassInitialize]
        public static void ClassInit(TestContext context)
        {
            WNDictionary.Container = MEFLoader.Load();
        }
       
        [TestMethod]
        public void IndexWordMapperGetAllTest()
        {
            IContentType<IIndexWord> content = ContentType<IIndexWord>.GetIndexContentType(POS.NOUN);
            var testParser = content.DataType.GetParser() as TestParserBase;
            testParser.Reset();

            // mock data provider
            Mock<IDataProvider<IIndexWord>> dataProviderMock = new Mock<IDataProvider<IIndexWord>>();
            dataProviderMock.Setup(dp => dp.IsOpen).Returns(false);
            dataProviderMock.Setup(dp => dp.Open()).Verifiable("Open was not called");

            // mock data source        
            Mock<IDataSource> dataSourceMock = new Mock<IDataSource>();
            dataProviderMock.Setup(dp => dp.GetSourceForContentType(content))
                .Returns(dataSourceMock.Object);

            // test AllLines
            string[] lines = new string[] { "one", "two", "three" };
            dataSourceMock.Setup(ds => ds.AllLines()).Returns(lines);

            IndexWordMapper indexMapperTest = new IndexWordMapper(dataProviderMock.Object);
            int cnt = 0;
            foreach (var item in indexMapperTest.GetAll(POS.NOUN))
            {
                Assert.AreEqual(lines[cnt++], item.Lemma);
            }
            dataProviderMock.Verify();
            Assert.IsTrue(testParser.Verify());
        }

        [TestMethod]
        public void IndexWordMapperGetByKeyTest()
        {
            // index word id param
            IIndexWordID indexWordID = new IndexWordID("test", POS.NOUN);

            // get ref to content type
            IContentType<IIndexWord> content = ContentType<IIndexWord>
                .GetIndexContentType(indexWordID.PartOfSpeech);
            // get ref to test parser
            var testParser = content.DataType.GetParser() as TestParserBase;
            testParser.Reset();

            // mock data provider
            Mock<IDataProvider<IIndexWord>> dataProviderMock = new Mock<IDataProvider<IIndexWord>>();
            // test IsOpen
            dataProviderMock.Setup(dp => dp.IsOpen).Returns(false);
            // test Open
            dataProviderMock.Setup(dp => dp.Open()).Verifiable("Open was not called");

            // mock data source
            Mock<IDataSource> dataSourceMock = new Mock<IDataSource>();
            dataProviderMock.Setup(dp => dp.GetSourceForContentType( content))
                .Returns(dataSourceMock.Object).Verifiable("get data source");

            // test ReadLine
            string lemma = indexWordID.Lemma;
            dataSourceMock.Setup(ds => ds.Search(lemma)).Returns("test");

            // run test
            IndexWordMapper indexMapperTest = new IndexWordMapper(dataProviderMock.Object);
            var result = indexMapperTest.GetByKey(indexWordID);

            dataProviderMock.Verify();
            Assert.AreEqual("test", result.Lemma);
            Assert.IsTrue(testParser.Verify());

        }

        [TestMethod]
        public void IndexWordMapperGetByKeyReturnsNullTest()
        {
            // index word id param
            IIndexWordID indexWordID = new IndexWordID("test", POS.NOUN);

            // get ref to content type
            IContentType<IIndexWord> content = ContentType<IIndexWord>
                .GetIndexContentType(indexWordID.PartOfSpeech);
            // get ref to test parser
            var testParser = content.DataType.GetParser() as TestParserBase;
            testParser.Reset();

            // mock data provider
            Mock<IDataProvider<IIndexWord>> dataProviderMock = new Mock<IDataProvider<IIndexWord>>();
            // test IsOpen
            dataProviderMock.Setup(dp => dp.IsOpen).Returns(false);
            // test Open
            dataProviderMock.Setup(dp => dp.Open()).Verifiable("Open was not called");

            // mock data source
            Mock<IDataSource> dataSourceMock = new Mock<IDataSource>();
            dataProviderMock.Setup(dp => dp.GetSourceForContentType(content))
                .Returns(dataSourceMock.Object).Verifiable("get data source");

            // test ReadLine
            string lemma = indexWordID.Lemma;
            string returnVal = null;
            dataSourceMock.Setup(ds => ds.Search(lemma)).Returns(returnVal);

            // run test
            IndexWordMapper indexMapperTest = new IndexWordMapper(dataProviderMock.Object);
            var result = indexMapperTest.GetByKey(indexWordID);

            dataProviderMock.Verify();
            Assert.IsNull(result);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetByKeyThrowsErrorWhenNullParameter()
        {
            // mock data provider
            Mock<IDataProvider<IIndexWord>> dataProviderMock = new Mock<IDataProvider<IIndexWord>>();
            IndexWordMapper indexMapperTest = new IndexWordMapper(dataProviderMock.Object);
            indexMapperTest.GetByKey(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetByKeyThrowsErrorWhenWrongTypeParameter()
        {
            // mock data provider
            Mock<IDataProvider<IIndexWord>> dataProviderMock = new Mock<IDataProvider<IIndexWord>>();
            IndexWordMapper indexMapperTest = new IndexWordMapper(dataProviderMock.Object);
            indexMapperTest.GetByKey(new Object());
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void GetAllThrowsErrorWhenNullParameter()
        {
            // mock data provider
            Mock<IDataProvider<IIndexWord>> dataProviderMock = new Mock<IDataProvider<IIndexWord>>();
            IndexWordMapper indexMapperTest = new IndexWordMapper(dataProviderMock.Object);
            indexMapperTest.GetAll(null).ToArray();
        }
    }
}
